#pragma once
#include <iostream>
#include <memory>
#include "Epoller.hpp"
#include "Socket.hpp"
#include "log.hpp"
#include"nocopy.hpp"

extern Log lg;
static const int defaultport = 8888;
uint32_t EVENT_IN = EPOLLIN;
uint32_t EVENT_OUT = EPOLLOUT;
static const int num = 64;

class EpollServer:public nocopy
{
public:
    EpollServer(uint16_t port = defaultport)
        : port_(port), listensock_(new Sock()), epoller_ptr(new EPoller())
    {
    }

    void Init()
    {
        listensock_->Socket();
        listensock_->Bind(port_);
        listensock_->Listen();
        lg(Info, "Init success!");
    }

    void Dispatcher(struct epoll_event revs[], int num)
    {
        for (int i = 0; i < num; i++)
        {
            uint32_t event = revs[i].events;
            int fd = revs[i].data.fd;
            if (event & EVENT_IN)
            {
                if (fd == listensock_->Fd())
                {
                    // accept
                    std::string clientip;
                    uint16_t clientport;
                    int newfd = listensock_->Accept(&clientip, &clientport);
                    if (newfd > 0)
                    {
                        // 我们不能直接读，更新数据
                        epoller_ptr->Epollerupdata(EPOLL_CTL_ADD, newfd, EVENT_IN);
                        lg(Info, "get a new link,client info:%s %d",clientip.c_str(),clientport);
                    }
                }
                else
                {
                    //read
                    char buffer[1024];
                    int n = read(fd, buffer, sizeof(buffer)-1);
                    if (n < 0)
                    {
                        lg(Error, "read error,fd:%d", fd);
                        epoller_ptr->Epollerupdata(EPOLL_CTL_DEL, fd, 0);
                        close(fd);
                    }
                    else if (n == 0)
                    {
                        lg(Info, "client close,me too,fd:%d", fd);
                        epoller_ptr->Epollerupdata(EPOLL_CTL_DEL,fd,0);
                        close(fd);
                    }
                    else
                    {
                        buffer[n]=0;
                        std::cout<<"get a message: "<<buffer<<std::endl;
                        // write
                        std::string out;
                        out+="echo: ";
                        out+=buffer;
                        write(fd,out.c_str(),out.size());
                    }
                }
            }
        }
    }

    void Start()
    {
        // 将listensock添加到epoll中，listensock和它关心的事件，添加到内核epoll模型的rb_tree
        epoller_ptr->Epollerupdata(EPOLL_CTL_ADD, listensock_->Fd(), EVENT_IN);
        struct epoll_event revs[num];
        for (;;)
        {
            int n = epoller_ptr->EpollWait(revs, num);
            // n就是就绪个数
            if (n == -1)
            {
                lg(Error, "epoller_ptr->EpollWait error,strerr:%s",strerror(errno));
            }
            else if (n == 0)
            {
                lg(Info, "time out...");
            }
            else
            {
                lg(Info, "event already,fd:%d", revs[0].data.fd);
                Dispatcher(revs, n);
            }
        }
    }



    ~EpollServer()
    {
        listensock_->Close();
    }

private:
    std::shared_ptr<Sock> listensock_;
    std::shared_ptr<EPoller> epoller_ptr;
    uint16_t port_;
};